In order to preclude any chance of data corruption, drivers that are affected must ensure that the IO4 flushes its cache following any DMA write to memory (input from a device). This is done by calling a new kernel function, io4_flush_cache(), in the interrupt routine immediately following completion of any DMA.
The prototype of io4_flush_cache() is
The argument to the function is any value returned by pio_mapaddr() that is related to the device doing the DMA. The kernel uses this address to locate the IO4 involved. The returned value is 0 when the operation is successful (or was not needed). It is 1 when the argument is not a valid address returned by pio_mapaddr().int io4_flush_cache(caddr_t any_PIO_mapaddr);
The function should be called immediately after the completion of a DMA input to memory. Typically the device produces an interrupt at the end of a DMA, and the function can be called from the interrupt hander. However, some devices can complete more than one DMA transaction per interrupt, and io4_flush_cache() should be called when each DMA completes. Put another way, if it is possible that a data transfer completed after an interrupt, then the driver should call io4_flush_cache() before marking the transaction as complete.
The io4_flush_cache() function does nothing and returns immediately in a machine that has only one IO4 board, and in a machine in which all IO4 boards have the hardware fix.
The kernel's VME interrupt handler calls io4_flush_cache() once on each VME interrupt. Thus a VME device driver only needs to call io4_flush_cache() in the event that it handles the completion of more than DMA transaction per interrupt. For example, a VME-based network driver that handles multiple packets per interrupt should call io4_flush_cache() once for each packet that completes.
Since this problem only affects Challenge/Onyx systems (including POWER Challenge, POWER Onyx, and POWER Challenge R10000), the software fix can and should be conditionally compiled on the compiler variable EVEREST, which is set by /var/sysgen/Makefile.kernio for the affected machines (see "Using /var/sysgen/Makefile.kernio").
The following is a skeletal example of fix code for a hypothetical driver:
#ifdef EVEREST extern void io4_flush_cache(void* anyPIOMapAddr); #endif caddr_t some_PIO_map_addr; hypothetical_edtinit(...) { ... some_PIO_map_addr = pio_mapaddr(my_piomap, some_dev_addr) ... } hypothetical_intr(...) { ... #ifdef EVEREST io4_flush_cache(some_PIO_map_addr); #endif ... }For another example, see the code of the example VME device driver under "Sample VME Device Driver".